#include "CoYPacketListener.h"

#include <string>
#include "osc/OscReceivedElements.h"
#include "osc/OscPacketListener.h"
#include "ip/UdpSocket.h"
#include "stdio.h"

CoYPacketListener::CoYPacketListener(ExtOSCThread* oscThread) {
    this->oscThread = oscThread;
}


void CoYPacketListener::ProcessMessage( const osc::ReceivedMessage& m,
                                const IpEndpointName& remoteEndpoint )
    {
        try{
            // example of parsing single messages. osc::OsckPacketListener
            // handles the bundle traversal.
            if( strcmp( m.AddressPattern(), "/test1" ) == 0 ){
                // example #1 -- argument stream interface
                osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
                bool a1;
                osc::int32 a2;
                float a3;
                const char *a4;
                args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage;

                cout << "received '/test1' message with arguments: "
                    << a1 << " " << a2 << " " << a3 << " " << a4 << endl;

            } else if( strcmp( m.AddressPattern(), "/test2" ) == 0 ){
                // example #2 -- argument iterator interface, supports
                // reflection for overloaded messages (eg you can call
                // (*arg)->IsBool() to check if a bool was passed etc).
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                bool a1 = (arg++)->AsBool();
                int a2 = (arg++)->AsInt32();
                float a3 = (arg++)->AsFloat();
                const char *a4 = (arg++)->AsString();
                if( arg != m.ArgumentsEnd() )
                    throw osc::ExcessArgumentException();

                cout << "received '/test2' message with arguments: "
                    << a1 << " " << a2 << " " << a3 << " " << a4 << endl;
            } else if( strcmp( m.AddressPattern(), "/addPeer" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                string user((arg++)->AsString());
                cout <<"Added peer: " << user<< endl;
                //emit userAdded(user);
            } else if( strcmp( m.AddressPattern(), "/removePeer" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                string user((arg++)->AsString());
                cout <<"Removed peer: " << user << endl;
                //emit userRemoved(user);
            } else if( strcmp( m.AddressPattern(), "/addSyncObject" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                string objectID = (arg++)->AsString();
                string type = (arg++)->AsString();
                string subType = (arg++)->AsString();

                cout << objectID << " " << type << " " << subType << " "<< endl;

                if(type.compare("Yig") == 0) {
                    if(subType.compare("SynthObject") == 0) {
                        const char* synthName = (arg++)->AsString();
                        int xPos, yPos;
                        float param1, param2;
                        xPos = (arg++)->AsInt32();
                        yPos = (arg++)->AsInt32();
                        param1 = (arg++)->AsFloat();
                        param2 = (arg++)->AsFloat();
                        cout << param2 << endl;
                        //emit addSynth(objectID, string(synthName), QPoint(xPos, yPos), param1, param2);
                        oscThread->addSynth(objectID, string(synthName), xPos, yPos, param1, param2);
                    } else if(subType.compare("CursorObject") == 0) {
                        //const char* objectID = (arg++)->AsString();
                        //float x =  (float) (arg++)->AsInt32();
                        //float y =  (float) (arg++)->AsInt32();
                        oscThread->addCursor(objectID,0.0,0.0);
                    }
                }

            } else if( strcmp( m.AddressPattern(), "/removeSyncObject" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                string objectID = (arg++)->AsString();
                string type = (arg++)->AsString();
                string subType = (arg++)->AsString();

                if(subType.compare("SynthObject") == 0) {
                    //emit removeSynth(objectID);
                    oscThread->removeSynth(objectID);
                } else if(subType.compare("CursorObject")) {
                    oscThread->removeCursor(objectID);
                }

                cout << "Removed SyncObject: " << objectID << type << subType << endl;
            } else if( strcmp( m.AddressPattern(), "/setSyncArg" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                string type;
                int numArgs = m.ArgumentCount();

                for(int i = 0; i < numArgs; i++){
                    if(i == (numArgs-1)){
                        type = string((arg++)->AsString());
                    } else {
                        arg++;
                    }
                }
                arg = m.ArgumentsBegin();

                if(type.compare("SynthObject")==0) {
                        string mapKey = string((arg++)->AsString());
                        int argNum = (arg++)->AsInt32();
                        switch(argNum) {
                        case 0:
                            //cout << "Synth Name" << (arg++)->AsString();
                            oscThread->synthNameSync(mapKey, (arg++)->AsString());
                            break;
                        case 1:
                            //cout << "Set xPos";
                            oscThread->updateSynthPositionX(mapKey, (arg++)->AsInt32());
                            break;
                        case 2:
                            //cout << "Set yPos";
                            oscThread->updateSynthPositionY(mapKey, (arg++)->AsInt32());
                            break;
                        case 3:
                            //cout << "Set Param1";
                            oscThread->updateSynthParam1(mapKey, (arg++)->AsFloat());
                            break;
                        case 4:
                            //cout << "Set Param2";
                            oscThread->updateSynthParam2(mapKey, (arg++)->AsFloat());
                            break;
                        case 5:
                            oscThread->updateSynthSelected(mapKey, (arg++)->AsString());
                            break;
                        }
                } else if(type.compare("CursorObject") == 0) {
                    string objectID = string((arg++)->AsString());
                    int argNum = (arg++)->AsInt32();
                    float value = (float)(arg++)->AsInt32();
                    switch(argNum) {
                        case 0:
                            //cout << objectID << " " << "Set xPos " << value << endl;
                            oscThread->setCursorX(objectID,value);
                            break;
                        case 1:
                            //cout << "Set yPos";
                            oscThread->setCursorY(objectID,value);
                            break;
                    }
                }
            } else if(strcmp( m.AddressPattern(), "/chat" ) == 0) {

                osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
                const char* message;
                args >> message >> osc::EndMessage;
                //emit receiveChat(string(message));
                oscThread->receiveChat(string(message));
            } else if(strcmp( m.AddressPattern(), "/audio" ) == 0) {
                osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin();
                vector<float> buffer;
                while(arg != m.ArgumentsEnd()) {
                    buffer.push_back((arg++)->AsFloat());
                }
                oscThread->setAudioBuffer(buffer);
           }
    } catch( osc::Exception& e ){
        // any parsing errors such as unexpected argument types, or
        // missing arguments get thrown as exceptions.
        cout << "error while parsing message: "
            << m.AddressPattern() << ": " << e.what() << endl;
    }
}
